#undef   _FILE_OFFSET_BITS
#define   _FILE_OFFSET_BITS   64
#include   <unistd.h>
#include   <dirent.h>
#include <string>
#include <stdio.h>
#include <iostream>
#include <mysql/mysql.h>
#include <map>
#include <time.h>

MYSQL mysql;
char xmlval[1024];
std::map<int, int> mapDict;			//字典查询数
std::map<int, int>::iterator cp;
std::map<std::string, int> userDictOne;	//用户查询数
std::map<std::string, int> userDictTwo;
std::map<std::string, int> keywordDictOne;	//关键字查询数
std::map<std::string, int> keywordDictTwo;

int parseDictToMap(const char* dict)
{
	int dn	= strlen(dict);
	int di	= 0;
	int dc	= 0;
	int dk	= 0;
	char dcs[4];	//字典ID不超过4位
	
	for (di=0; di<dn; di++ )
	{
		if (dict[di]=='|')
		{
			dcs[dk]	= '\0';
			dc		= atoi(dcs);
			cp	= mapDict.find(dc);
			if (cp != mapDict.end())
			{
				cp->second += 1;
			}
			else
			{
				mapDict.insert(std::pair<int, int>(dc,1));
			}
			dk	= 0;
			continue;
		}
		else
		{
			dcs[dk]	= dict[di];
			dk++;
		}
	}
	return 0;
}

//分离出xml标签中的内容
int getContent(char* s, char* b, char* e)
{
	xmlval[0] = '\0';
	const char* sfound;
	const char* efound;
	int i=0, x=0, y=0, z=0, n=0;
	x	= strlen(s);
	y	= strlen(b);
	if (x < 2) return 0;
	if (x < y) return 0;
	sfound	= strstr(s, b);
	//std::cout<<sfound<<std::endl;
	efound	= strstr(s, e);
	if(sfound != NULL && efound != NULL)
	{
		i	= strlen(sfound)-strlen(efound);
		z	= 0;
		for (n=y; n<i; n++)
		{
			xmlval[z] =sfound[n];
			z++;
		}
		xmlval[z] = '\0';
	}
	else
	{
		xmlval[z] = '\0';
		return -1;
	}
	//std::cout<<xmlval<<std::endl;
	return 0;
}


char dec2hexChar(short int n) 
{
	if ( 0 <= n && n <= 9 ) 
	{
		return char( short('0') + n );
	} 
	else if ( 10 <= n && n <= 15 ) 
	{
		return char( short('A') + n - 10 );
	} else 
	{
		return char(0);
	}
}

short int hexChar2dec(char c) 
{
	if ( '0'<=c && c<='9' ) 
	{
		return short(c-'0');
	} 
	else if ( 'a'<=c && c<='f' ) 
	{
		return ( short(c-'a') + 10 );
	} 
	else if ( 'A'<=c && c<='F' ) 
	{
		return ( short(c-'A') + 10 );
	} else 
	{
		return -1;
	}
}

std::string escapeURL(const std::string &URL)
{
	std::string result = "";
	for ( unsigned int i=0; i<URL.size(); i++ ) 
	{
		char c = URL[i];
		if (
		( '0'<=c && c<='9' ) ||
		( 'a'<=c && c<='z' ) ||
		( 'A'<=c && c<='Z' ) ||
		c=='/' || c=='.'
		) {
		result += c;
		} else 
		{
			int j = (short int)c;
			if ( j < 0 ) 
			{
				j += 256;
			}
			int i1, i0;
			i1 = j / 16;
			i0 = j - i1*16;
			result += '%';
			result += dec2hexChar(i1);
			result += dec2hexChar(i0);
		}
	}
	return result;
}

std::string deescapeURL(const std::string &URL) 
{
	std::string result = "";
	for ( unsigned int i=0; i<URL.size(); i++ ) 
	{
		char c = URL[i];
		if ( c != '%' ) 
		{
			result += c;
		} else 
		{
		char c1 = URL[++i];
		char c0 = URL[++i];
		int num = 0;
		num += hexChar2dec(c1) * 16 + hexChar2dec(c0);
		result += char(num);
		}
	}
	return result;
}

int dbClose()
{
	mysql_close(&mysql);
	return 0;
}

int insertLog(char* sql)
{
	MYSQL_ROW m_row;
	MYSQL_RES *m_res;
	if (mysql_query(&mysql,sql) !=0)
	{
		return -5;
	}
	m_res = mysql_store_result(&mysql);
	mysql_free_result(m_res);
	return 1;
}



int main(int argc, char *argv[])
{
	FILE *fp, *fpr;
	int i=0, j=0, k=0, y=0, x=0;
	int num = 0;
	char linebuffer[4096];
	std::map<std::string, int>::iterator useriter;
	std::map<std::string, int>::iterator keyiter;
	
	char sqlstr[2048];
	char host[32]="localhost";
	char user[32]="googleciba";
	char passwd[32]="googleandiciba2008count";
	//char passwd[32]	= "tonerx";
	char dbname[32]="goodict";

	unsigned long z=0;
	time_t slt;
	time_t elt;
	long int u=0;
	char timebuffer[100];
	struct tm *ptr;
	slt     = time(NULL);
	ptr     = localtime(&slt);
	strftime(timebuffer,100,"%Y-%m-%d %H:%M:%S",ptr);
	std::cout<<"Start at:"<<timebuffer<<std::endl;

	char logfile[255];
	const char* processdate;
	if (argc > 1)
	{
		processdate	= argv[1];
	}
	else
	{
		slt = time(NULL) - 86400;
		strftime(timebuffer,12,"%Y-%m-%d",localtime(&slt));
		processdate	= timebuffer;
	}
	sprintf(logfile, "/data/app/goodict/log/%s/access.log",processdate);
	//std::cout<<logfile<<std::endl;
	fp	= fopen(logfile, "r");
	if (fp == NULL)
	{
		std::cout<<"Can't open the file:"<<logfile<<std::endl;
		exit(0);
	}
	//std::cout<<(fp==NULL)<<std::endl;
	fpr	= fopen("result.txt", "w");

	char* log_ip;
	char* log_time;
	char* log_get;
	char* log_get_decode;
	char* log_stat;
	char* log_len;
	char* log_reffer;
	int querytype[2]	= {0,0};
	int t	= 0;
	long long totalsize=0;
	char str_time[20];
	std::string classid;
	std::string kword;
	std::string dictstr;
	struct tm* tmp_time = (struct tm*)malloc(sizeof(struct tm));
	
	while(fgets(linebuffer, 4096, fp))
	{
		z++;
		if(strlen(linebuffer) < 20)
		{
			continue;
		}

		log_ip = strtok(linebuffer," ");
		strtok(NULL," ");
		strtok(NULL," ");
		log_time	= strtok(NULL," ");
		str_time[0]	= '\0';
		strncpy(str_time,log_time+1,20);
		strptime(str_time,"%d/%b/%Y:%h:%M:%s",tmp_time);
		//std::cout<<strlen(str_time)<<std::endl;
		//std::cout<<mktime(tmp_time)<<std::endl;
		strtok(NULL," ");
		strtok(NULL," ");
		log_get	= strtok(NULL," ");
		if(log_get == NULL || log_get == "-")
		{
			continue;
		}
		strtok(NULL," ");
		log_stat	= strtok(NULL," ");
		log_len	= strtok(NULL," ");
		if (log_len == NULL) continue;
		totalsize	= atoi(log_len) + totalsize;
		log_reffer	= strtok(NULL," ");
		log_get_decode	= (char*)deescapeURL(log_get).c_str();
		getContent(log_get_decode,(char*)"<class>",(char*)"</class>");
		classid	= xmlval;
		getContent(log_get_decode, (char*)"<data>", (char*)"</data>");
		kword	= xmlval;
		if (kword.empty()) continue;
		//fputs(kword.c_str(), fpr);
		//fputs("\n", fpr);
		//sfound	= strstr(s, b);
		if (strstr(log_get_decode, "&t=1") != NULL)
		{
			querytype[0]	+= 1;
			t			= 1;
		}
		else
		{
			querytype[1]	+= 1;
			t			= 2;
		}
		getContent(log_get_decode, (char*)"<dictid>", (char*)"</dictid>");
		dictstr	= xmlval;
		//parseDict(dictstr.c_str());
		parseDictToMap(dictstr.c_str());
		//std::cout<<kword<<std::endl;

		//分解词典-不用分解，使用scanf可搞定。
		//sprintf(sqlstr,"insert into rk_logs set user_ip='%s', restat='%s', relenth='%s',keyword='%s'",log_ip,log_stat,log_len,kword.c_str());
		//std::cout<<sqlstr<<std::endl;
		//exit(0);
		//insertLog(sqlstr);
		if (t == 1)
		{
  			useriter	= userDictOne.find(log_ip);
			keyiter	= keywordDictOne.find(kword);
			if (useriter != userDictOne.end())
			{
				useriter->second += 1;
			}
			else
			{
				userDictOne.insert(std::pair<std::string, int>(log_ip, 1));
			}
			if (keyiter != keywordDictOne.end())
			{
				keyiter->second += 1;
			}
			else
			{
				keywordDictOne.insert(std::pair<std::string, int>(kword, 1));
			}
		}
		else
		{
			useriter	= userDictTwo.find(log_ip);
			keyiter	= keywordDictTwo.find(kword);
			if (useriter != userDictTwo.end())
			{
				useriter->second += 1;
			}
			else
			{
				userDictTwo.insert(std::pair<std::string, int>(log_ip, 1));
			}
			if (keyiter != keywordDictTwo.end())
			{
				keyiter->second += 1;
			}
			else
			{
				keywordDictTwo.insert(std::pair<std::string, int>(kword, 1));
			}
		}
	}

	fclose(fp);
	fclose(fpr);

	if( mysql_init(&mysql) == NULL )
	{
		std::cout<<"inital mysql handle error"<<std::endl;
		return -6;
	}
	if (mysql_real_connect(&mysql,host,user,passwd,dbname,0,NULL,0) == NULL)
	{
		std::cout<<"Failed to connect to database: Error: "<<mysql_error(&mysql)<<std::endl;
		return -7;
	}
	if (mysql_query(&mysql,"set names utf8") !=0)
	{
		std::cout<<"Query error:"<<mysql_error(&mysql)<<std::endl;
		return -5;
	}

	std::map<int,int>::iterator iter;
	sqlstr[0]	= '\0';
	for (iter=mapDict.begin();iter != mapDict.end();iter++)
	{
		//std::cout<<iter->first<<" "<<iter->second<<std::endl;
		sprintf(sqlstr, "insert into dictrank_dictdata (dict_id_id, query_num, query_date) values('%d', '%d', '%s')",iter->first, iter->second, processdate);
		//std::cout<<sqlstr<<std::endl;
		insertLog(sqlstr);
	}

	//用户字典查询数
	sqlstr[0] = '\0';
	insertLog("truncate table dictrank_userqueryonetmp");
	for(useriter = userDictOne.begin(); useriter != userDictOne.end(); useriter++)
	{		//std::cout<<useriter->first<<":"<<useriter->second<<std::endl;
		sprintf(sqlstr, "insert into dictrank_userqueryonetmp (user_ip, query_num, query_date) values('%s', '%d', '%s')",useriter->first.c_str(), useriter->second, processdate);
		insertLog(sqlstr);
	}
	sqlstr[0] = '\0';
	insertLog("truncate table dictrank_userquerytwotmp");
	for(useriter = userDictTwo.begin(); useriter != userDictTwo.end(); useriter++)
	{		//std::cout<<useriter->first<<":"<<useriter->second<<std::endl;
		sprintf(sqlstr, "insert into dictrank_userquerytwotmp (user_ip, query_num, query_date) values('%s', '%d', '%s')",useriter->first.c_str(), useriter->second, processdate);
		insertLog(sqlstr);
	}

	//关键字查询数
	sqlstr[0] = '\0';
	insertLog("truncate table dictrank_keywordtodayone");
	for(keyiter = keywordDictOne.begin(); keyiter != keywordDictOne.end(); keyiter++)
	{		//std::cout<<keyiter->first<<":"<<keyiter->second<<std::endl;
		sprintf(sqlstr, "insert into dictrank_keywordtodayone (keyword, query_num) values('%s', '%d')", keyiter->first.c_str(), keyiter->second);
		insertLog(sqlstr);
	}
	sqlstr[0] = '\0';
	insertLog("truncate table dictrank_keywordtodaytwo");
	for(keyiter = keywordDictTwo.begin(); keyiter != keywordDictTwo.end(); keyiter++)
	{		//std::cout<<keyiter->first<<":"<<keyiter->second<<std::endl;
		sprintf(sqlstr, "insert into dictrank_keywordtodaytwo (keyword, query_num) values('%s', '%d')", keyiter->first.c_str(), keyiter->second);
		insertLog(sqlstr);
	}

	//字典查询数
	sqlstr[0] = '\0';
	sprintf(sqlstr, "insert into dictrank_querytype(query_search_num, query_get_num, query_date) values('%d', '%d', '%s')",querytype[0] ,querytype[1], processdate);
	insertLog(sqlstr);
	
	elt     = time(NULL);
	ptr     = localtime(&elt);
	strftime(timebuffer,100,"%Y-%m-%d %H:%M:%S",ptr);
	std::cout<<"End at:"<<timebuffer<<" for "<<z<<" rows."<<std::endl;
	u=elt-slt;
	u=u<=0?1:u;
	std::cout<<"Total:"<<u<<"s for "<<z<<" rows.  avg:"<<(z/u)<<"row/s. Total response size:"<<(totalsize/1048576)<<"MB."<<std::endl;
	dbClose();
	return 0;
}




